package gao.xiaolei.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import gao.xiaolei.service.AuthVersionService;
import gao.xiaolei.dto.JwtDto;
import gao.xiaolei.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.function.Consumer;

@Component
public class AuthFilter extends ZuulFilter {

    @Autowired
    private AntPathMatcher antPathMatcher;

    @Autowired
    private RestTemplate restTemplate;

    @Resource(name = "AuthVersionService")
    private AuthVersionService authVersionService;

    // 表示将在什么阶段阶段执行
    @Override
    public String filterType() {
        return "pre";//路由之前执行
    }

    //执行优先级
    @Override
    public int filterOrder() {
        return 0;
    }

    // 过滤器执行条件
    @Override
    public boolean shouldFilter() {
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        String requestUrl = request.getServletPath();//获取请求路径
        if (antPathMatcher.match("/training-web-service/login", requestUrl) || antPathMatcher.match("/training-auth-manage-service/login", requestUrl) || antPathMatcher.match("/training-web-service/register", requestUrl) || antPathMatcher.match("/training-auth-manage-service/register", requestUrl) || antPathMatcher.match("/training-web-service/static/**", requestUrl) || (antPathMatcher.match("/training-image-manage-service/**", requestUrl) && "GET".equals(request.getMethod()) || (antPathMatcher.match("/testConfigFile", requestUrl))))//如果是登陆或者注册或者静态资源获取或者获取图片服务器图片则不拦截
            return false;
        return true;
    }

    //过滤执行的逻辑
    @lombok.SneakyThrows
    @Override
    public Object run() throws ZuulException {
        //获取上下文
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        String requestUrl = request.getServletPath();//获取请求路径
        String method = request.getMethod();
//        if (antPathMatcher.match("/training-auth-manage-service/login", requestUrl)) {//如果是登陆获取token的话则要加上版本号
//            request.getParameterMap();//网上说如果不这样get一下的话下面的Map就出不来,但我get了也还是null
//            Map<String, List<String>> requestQueryParams = currentContext.getRequestQueryParams();
//            if (requestQueryParams == null) {
//                requestQueryParams = new HashMap<>();
//            }
//            //将要新增的参数添加进去,被调用的微服务可以直接 去取,就想普通的一样,框架会直接注入进去
//            ArrayList<String> arrayList = new ArrayList<>(1);
//            arrayList.add("0");
//            requestQueryParams.put("version", arrayList);
//            currentContext.setRequestQueryParams(requestQueryParams);
//            return null;
//        }
        if (antPathMatcher.match("/training-auth-manage-service/logout", requestUrl)) {//如果是退出登录则直接销毁Cookie即可
            currentContext.setSendZuulResponse(false);
            Cookie cookie = new Cookie("access_token", null);
            cookie.setPath("/");
            cookie.setMaxAge(0);
            currentContext.getResponse().addCookie(cookie);
            currentContext.getResponse().sendRedirect("/training-web-service/login");//重定向到登陆页面
            return null;
        }
        Cookie[] cookies = request.getCookies();
        String access_token = null;
        if (cookies != null)
            access_token = Arrays.stream(cookies).filter(c -> "access_token".equals(c.getName())).findFirst().orElse(new Cookie("access_token", "")).getValue();
        if (JwtUtil.verify(access_token)) {
            showDetails(request, access_token);
            Integer version = JwtUtil.getVersion(access_token);
            String userId = JwtUtil.getUserId(access_token);
            if (!authVersionService.versionCheck(userId, version)) {//判断用户的权限有没有更新,更新了的话则刷新access_token
                JwtDto refreshToken = restTemplate.getForObject("http://training-auth-manage-service/refresh/".concat(userId), JwtDto.class);
                Cookie cookie = new Cookie("access_token", refreshToken.getToken());
                cookie.setMaxAge(24 * 60 * 60 * 1000);
                cookie.setPath("/");//设置作用域,如果不设置cookie的path就是/user,那么去请求/user的父亲和兄弟路径就不会带上该cookie
                currentContext.getResponse().addCookie(cookie);
            }
            String[] roles = JwtUtil.getRoles(access_token);//获取token的角色
            String[] auths = JwtUtil.getAuth(access_token);//获取token的权限点
            Map<String, String[]> transientAuth = null;
            if (JwtUtil.getTransientAuth(access_token) != null)
                transientAuth = JwtUtil.getTransientAuth(access_token);//获取token的临时权限点
            String auth = null;
            int readOnly, index;
            for (int i = 0, length = auths.length; i < length; i++) {
                if (auths[i] != null) {
                    index = auths[i].indexOf("---");
                    auth = auths[i].substring(0, index);
                    readOnly = Integer.valueOf(auths[i].substring(index + 3));
                    if (antPathMatcher.match(auth, requestUrl)) {//token有此权限
                        if ("GET".equals(method))//并且如果是GET操作的话直接放行
                            return null;
                        else {//如果不是get操作
                            if (readOnly != 1)//但拥有的权限不是只读权限
                                return null;//就可以直接放行
                        }
                    }
                }
            }
            if (transientAuth != null) {//判断是否有临时赋予的权利
                Set<Map.Entry<String, String[]>> trans = transientAuth.entrySet();
                for (Map.Entry<String, String[]> tran : trans) {
                    if (antPathMatcher.match(tran.getKey(), requestUrl))//token有此权限,直接放行
                        return null;
                }
            }
            //过滤该请求，不往下级服务去转发请求，到此结束
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseStatusCode(401);
            currentContext.setResponseBody("{\"result\":\"accessToken无此权限!\"}");
            currentContext.getResponse().setContentType("text/html;charset=UTF-8");
        } else {
            System.out.println("access_tocken无效");
            //过滤该请求，不往下级服务去转发请求，到此结束
            currentContext.setSendZuulResponse(false);
            currentContext.getResponse().sendRedirect("/training-web-service/login");//重定向到登陆页面
        }
        //这里return的值没有意义，zuul框架没有使用该返回值
        return null;
    }

    //打印相关信息
    private void showDetails(HttpServletRequest request, String access_token) {
        Consumer c = System.out::println;
        c.accept("access_tocken有效");
        String requestUrl = request.getServletPath();
        c.accept("请求的路径:".concat(requestUrl));
        c.accept("用户id:".concat(JwtUtil.getUserId(access_token)));
        String[] roles = JwtUtil.getRoles(access_token);
        c.accept("用户角色:");
        for (int i = 0, length = roles.length; i < length; i++) {
            c.accept(roles[i]);
        }
        c.accept("用户权限点:");
        String[] auths = JwtUtil.getAuth(access_token);
        for (int i = 0, length = auths.length; i < length; i++) {
            c.accept(auths[i]);
        }
        if (JwtUtil.getTransientAuth(access_token) != null)
            c.accept("用户暂时权限点:".concat(JwtUtil.getTransientAuth(access_token).toString()));
    }
}
